// Copyright (C) 2024 Kumo inc.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <kthread/internal/kthread.h>

namespace kthread {

    template<typename T>
    class GetLeakySingleton {
    public:
        static T *_instance;
        static kthread_once_t *g_create_leaky_singleton_once;

        static void create_leaky_singleton();
    };

    template<typename T>
    T *GetLeakySingleton<T>::_instance = nullptr;

    template<typename T>
    kthread_once_t *GetLeakySingleton<T>::g_create_leaky_singleton_once
            = new kthread_once_t;

    template<typename T>
    void GetLeakySingleton<T>::create_leaky_singleton() {
        _instance = new T;
    }

// To get a never-deleted singleton of a type T, just call
// kthread::get_leaky_singleton<T>(). Most daemon (b)threads
// or objects that need to be always-on can be created by
// this function. This function can be called safely not only
// before main() w/o initialization issues of global variables,
// but also on kthread with hanging operation.
    template<typename T>
    inline T *get_leaky_singleton() {
        using LeakySingleton = GetLeakySingleton<T>;
        kthread_once(LeakySingleton::g_create_leaky_singleton_once,
                     LeakySingleton::create_leaky_singleton);
        return LeakySingleton::_instance;
    }

} // namespace kthread

